package com.tfleo.mealssenger;

import com.tfleo.mealssenger.R;
import com.tfleo.mealssenger.utility.ImageTools;
import com.tfleo.mealssenger.utility.IntentExtras;
import com.tfleo.mealssenger.utility.NetworkTools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.provider.MediaStore.Images.Media;
import android.provider.Settings.Secure;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.ViewSwitcher;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ImageView.ScaleType;
import android.widget.Toast;

/**
 * Activity for adding new Food object to Mealssenger server.
 * 
 * @author Theodore Felix Leo
 */
public class AddFoodActivity extends Activity {
	private static final String TAG = "AddFoodActivity";
	private static final int CAMERA_REQUEST = 1;
	private static final String UPLOAD_URL = 
			Main.SERVER_URL + "image_upload.php?op=2"; //op=2 store in 'SERVER/img/food/'
	
	private ViewSwitcher vSwitcher;
	private Spinner vCategory;
	private AutoCompleteTextView vTag;
	private EditText vName;
	private EditText vDescription;
	private Button vBack;
	private Button vSubmit;
	private Button vNext;
	private ImageView vFoodImage;
	
	private Context mContext;
	
	private File mImageDir;
	private File mCurImageDir;
	private File mRoot;
	private Uri mOutputFileUri;
	private Bitmap mPhoto;
	
	//These are used in case filename uploaded set to be the same with local filename
	//Now: image filename in server is [ID].jpg
	private String mImageFileName;
	/*private String mCurImageFileName;*/
	
	private String mName;
	private String mDescription;
	private int mLocationId;
	private String mLocationName;
	private int mWeight;
	private String mCategory;
	private String mTag;
	
	private String[] mTagName;
	private HashMap<String, Integer> mTagList = new HashMap<String, Integer>();
	
	private boolean mImgAvailable = false;
	private int mLastInsertId;
	
	private String mAuth;
	private int mUserId;
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	    setContentView(R.layout.add_food);
	    mContext = this;
	    vSwitcher = (ViewSwitcher) findViewById(R.id.switcher);
	    
	    mAuth = Secure.getString(this.getContentResolver(), Secure.ANDROID_ID); //for authentication
	    mUserId = getSharedPreferences(Main.USER_DATA, MODE_PRIVATE).getInt(Main.USER_ID, 0);
	    
	    //Root directory to store image
	    mRoot = new File(Environment.getExternalStorageDirectory() + File.separator 
	    		+ "Mealssenger" + File.separator);
	    mRoot.mkdirs();
	    
	    Bundle extras = getIntent().getExtras();
        if(extras != null) {
        	mLocationId = extras.getInt(IntentExtras.PLACE_ID);
        	mLocationName = extras.getString(IntentExtras.PLACE_NAME);
        }
		
        //Filename for image using random number
	    Random filename = new Random();
        mImageDir = new File(mRoot, Integer.toString(filename.nextInt()) + ".jpg");
        mOutputFileUri = Uri.fromFile(mImageDir);
	
        vName = (EditText) findViewById(R.id.name);
	    vDescription = (EditText) findViewById(R.id.desc);
	    
	    vFoodImage = (ImageView) findViewById(R.id.image);
	    vFoodImage.setOnClickListener(new OnClickListener() {
	    	public void onClick(View v) {
	    		if(mPhoto != null) {
	    			mPhoto.recycle();
	    		}
	    		
	    		Random filename = new Random();
	    		mImageFileName = Integer.toString(filename.nextInt()) + ".jpg";
	            mImageDir = new File(mRoot, mImageFileName);
	            mOutputFileUri = Uri.fromFile(mImageDir);
	    		
	    		Intent i = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); 
	    		i.putExtra(MediaStore.EXTRA_OUTPUT, mOutputFileUri);
	    		startActivityForResult(i, CAMERA_REQUEST); 
	    	}
	    });
	    
	    
	    vNext = (Button) findViewById(R.id.next);
	    vNext.setOnClickListener(new OnClickListener() {
	    	public void onClick(View v) {
	    		//Force to have name
				if((mName = vName.getText().toString()).trim().equals("")) {
					Toast.makeText(mContext, "Error: Please specify food name!", Toast.LENGTH_SHORT).show();
					return;
				}
				
				//Empty description is ok
				if((mDescription = vDescription.getText().toString()).trim().equals("")) {
					mDescription = "";
				}
				
				//Force to have image
				if(!mImgAvailable) {
					Toast.makeText(mContext, "Error: No image taken!", Toast.LENGTH_SHORT).show();
					return;
				}

				HandleTagTask task = new HandleTagTask();
				task.execute();
				
				vSwitcher.showNext();
				
	    	}
	    });
	    
	    vCategory = (Spinner) findViewById(R.id.category);
        ArrayAdapter<CharSequence> foodCategoryAdapter = ArrayAdapter.createFromResource(
	            this, R.array.food_category_array, android.R.layout.simple_spinner_item);
	    foodCategoryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
	    
	    vCategory.setAdapter(foodCategoryAdapter);
	    vCategory.setOnItemSelectedListener(new OnItemSelectedListener() {       
	    	public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
	            mCategory = parent.getItemAtPosition(pos).toString();
	        }

	        public void onNothingSelected(AdapterView<?> parent) {
	        	mCategory = parent.getItemAtPosition(0).toString();
	        }

	    });
	    
	    vTag = (AutoCompleteTextView) findViewById(R.id.tag);
	    
	    vBack = (Button) findViewById(R.id.back);
	    vBack.setOnClickListener(new OnClickListener() {
	    	public void onClick(View v) {
	    		vSwitcher.showPrevious();
	    	}
	    });
	    
	    vSubmit = (Button) findViewById(R.id.submit);
	    vSubmit.setOnClickListener(new OnClickListener() {
	    	public void onClick(View v) {
	    		//TODO: if new tag
	    		if((mTag = vTag.getText().toString()).trim().equals("")) {

				}
	    		
	    		if(mTagList.get(mTag) == null) {
	    			mWeight = 1;
	    		} else {
	    			mWeight = mTagList.get(mTag);
	    		}
	    		
	    		SubmitTask task = new SubmitTask();
	    		task.execute();
	    	}
	    });
	    
	    if(!NetworkTools.isNetworkAvailable(mContext)) {
	    	Toast.makeText(getApplicationContext(),
					"Warning: Network is currently unavailable!", Toast.LENGTH_LONG).show();
	    }
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
        if (requestCode == CAMERA_REQUEST) {  
        	if (resultCode == RESULT_OK) {
        		try {
        			getContentResolver().notifyChange(mOutputFileUri, null);       			
        			ImageTools.compress(getContentResolver(), mOutputFileUri, mImageDir);
        			
        			//Set thumbnail
        			mPhoto = Media.getBitmap(getContentResolver(), mOutputFileUri);
        			vFoodImage.setImageBitmap(mPhoto);
        			vFoodImage.setScaleType(ScaleType.CENTER_CROP);
    	            
        			mCurImageDir = mImageDir;
        			/*mCurImageFileName = mImageFileName;*/
        			mImgAvailable = true;
    	        } catch(FileNotFoundException e) {
    	            e.printStackTrace();
    	        } catch(IOException e) {
    	            e.printStackTrace();
    	        } catch(Exception e) {
    	            e.printStackTrace();
    	        }
            } else if (resultCode == RESULT_CANCELED) {
            	if(mImgAvailable) {
            		//Reuse last image if available
	            	mImageDir = mCurImageDir;
	            	/*mImageFileName = mCurImageFileName;*/
	            	mOutputFileUri = Uri.fromFile(mImageDir);
	            	try {
	        			getContentResolver().notifyChange(mOutputFileUri, null);       			

	        			mPhoto = Media.getBitmap(getContentResolver(), mOutputFileUri);
	        			vFoodImage.setImageBitmap(mPhoto);
	        			vFoodImage.setScaleType(ScaleType.CENTER_CROP);
	    	            
	        			mCurImageDir = mImageDir;
	        			mImgAvailable = true;
	    	        } catch(FileNotFoundException e) {
	    	            e.printStackTrace();
	    	        } catch(IOException e) {
	    	            e.printStackTrace();
	    	        } catch(Exception e) {
	    	            e.printStackTrace();
	    	        }
            	}
            } else {
            	Toast.makeText(mContext, "Error: Failed to take picture!", Toast.LENGTH_SHORT).show();
            }
        }  
    } 
	
	/**
	 * Add new food data to server.
	 * 
	 * @param name Name of food
	 * @param locationId Location ID where this food is
	 * @param locationName Location name where this food is
	 * @param description Description of food
	 * @param category Category of food
	 * @param tag Tag of food
	 * @param franchised Whether this food is franchised food
	 * 
	 * @return true if successful, false otherwise
	 */
	private boolean addFood(String name, int locationId, String locationName, String description, 
			String category, String tag) {
		HttpClient httpclient = new DefaultHttpClient();
		HttpPost httppost = new HttpPost(Main.SERVER_URL + "food/add");
		
		if(!NetworkTools.isNetworkAvailable(mContext)) {
	    	Toast.makeText(getApplicationContext(),
					"Warning: Network is currently unavailable!", Toast.LENGTH_LONG).show();
	    	return false;
	    }
		
		try {
			//TODO: server api field call
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
			nameValuePairs.add(new BasicNameValuePair("name", name));
			nameValuePairs.add(new BasicNameValuePair("location_id", Integer.toString(locationId)));
			nameValuePairs.add(new BasicNameValuePair("location_name", locationName));
			nameValuePairs.add(new BasicNameValuePair("description", description));
			nameValuePairs.add(new BasicNameValuePair("category", category));
			nameValuePairs.add(new BasicNameValuePair("tag", tag));
			nameValuePairs.add(new BasicNameValuePair("weight", Integer.toString(mWeight)));
			nameValuePairs.add(new BasicNameValuePair("user_id", Integer.toString(mUserId)));
			nameValuePairs.add(new BasicNameValuePair("auth", mAuth));
			httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

			//Execute HTTP Post Request
			ResponseHandler<String> responseHandler = new BasicResponseHandler();
			String body = httpclient.execute(httppost, responseHandler);
			JSONObject jo = new JSONObject(body);
			
			//Image file name in server is equal to its ID
			if((mLastInsertId = jo.getInt("code")) > 0) {
				ImageTools.upload(mImageDir, UPLOAD_URL, Integer.toString(mLastInsertId) + ".jpg");
				return true;
			} else {
				return false;
			}
		} catch(JSONException e){
			e.printStackTrace();
		} catch(IOException e) {
			e.printStackTrace();
		} catch(Exception e) {
			e.printStackTrace();
		}
		
		return false;
	}
	
	/**
	 * Task to handle submission of data to server.
	 * 
	 */
	private class SubmitTask extends AsyncTask<Void, Void, Boolean> {
		@Override
		protected Boolean doInBackground(Void... params) {
			if(addFood(mName, mLocationId, mLocationName, mDescription, mCategory, mTag)) {
				return true;
			}
			return false;
		}
		
		@Override
		protected void onPostExecute(Boolean result) {
			if(result) {
				mPhoto.recycle();
//				System.gc();
//				Intent i = new Intent(mContext, Main.class); 
//				i.putExtra("tab", 1);
//				i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
//				mContext.startActivity(i);
				setResult(1);
				finish();
			} else {
				Toast.makeText(getApplicationContext(), "Error: Failed to submit to server", 
						Toast.LENGTH_SHORT).show();
			}
	    }
		
	}
	
	/**
	 * Retrieve all tags from server. Store all tags on 
	 * string array and store tag details on hashmap.
	 */
	private void getTag() {
		try {
			URL url = new URL(Main.SERVER_URL + "get_tag.php");
			URLConnection conn = url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		
			String responseBody;
			while ((responseBody = in.readLine()) != null) {
				JSONArray ja = new JSONArray(responseBody);
				mTagName = new String[ja.length()];
				//mTagWeight = new int[ja.length()];
				for (int i = 0; i < ja.length(); i++) {
					JSONObject jo = (JSONObject) ja.get(i);
					mTagName[i] = jo.getString("tag");
					//mTagWeight[i] = jo.getInt("weight");
					mTagList.put(jo.getString("tag"), jo.getInt("weight"));
				}
			}
			
		} catch(MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Retrieve tag guessed by server.
	 * 
	 * @param name Name of food to be guessed
	 * @return true if a tag is guessed, false otherwise
	 */
	private boolean guessTag(String name) {
		try {
			name = URLEncoder.encode(name, "utf-8"); //Embed space
			URL url = new URL(Main.SERVER_URL + "guess_tag.php?name=" + name);
			URLConnection conn = url.openConnection();
			BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
		
			String response;
			while ((response = in.readLine()) != null) {
				JSONObject jo = new JSONObject(response);
				
				if(jo.getInt("result") == 1) {
					mTag = jo.getString("tag");
					mWeight = jo.getInt("weight");
					Log.i(TAG, "A tag is guessed");
					return true;
				} else {
					mTag = "";
					mWeight = 1;
					Log.i(TAG, "Couldn't guess tag");
					return false;
				}
			}
		} catch(MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			e.printStackTrace();
		}
		
		return false;
	}
	
	/**
	 * Task to handle tag guessing. This task also retrieves all tag from
	 * server. If a tag is guessed, set it to text box
	 *
	 */
	private class HandleTagTask extends AsyncTask<Void, Void, Boolean> {
		@Override
		protected Boolean doInBackground(Void... params) {
			boolean result = false;
			if(guessTag(mName)) {
				result = true;
			} else {
				result = false;
			}
			getTag();
			return result;
		}
		
		@Override
		protected void onPostExecute(Boolean result) {
			ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext, R.layout.tag_list, mTagName);
		    vTag.setAdapter(adapter);
		    vTag.setOnItemSelectedListener(new OnItemSelectedListener() {
				@Override
				public void onItemSelected(AdapterView<?> parent, View view,
						int position, long id) {
					//mWeight = mTagWeight[position];
					mTag = mTagName[position];
					//mWeight = mTagList.get(mTag);
				}

				@Override
				public void onNothingSelected(AdapterView<?> parent) {
					// TODO Auto-generated method stub		
				}
		    });
		    
			if(result) {
				vTag.setText(mTag);
			}
	    }
	}
}
